home *** CD-ROM | disk | FTP | other *** search
- Subject: v25i009: trn 2.0 - threaded newsreader based on rn 4.4, Part06/13
- Newsgroups: comp.sources.unix
- Approved: vixie@pa.dec.com
-
- Submitted-by: davison@borland.com (Wayne Davison)
- Posting-number: Volume 25, Issue 9
- Archive-name: trn/part06
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 6 (of 13)."
- # Contents: Pnews.SH help.c mt-read.c rn.c util.c
- # Wrapped by vixie@cognition.pa.dec.com on Tue Dec 3 16:34:53 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Pnews.SH' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Pnews.SH'\"
- else
- echo shar: Extracting \"'Pnews.SH'\" \(17117 characters\)
- sed "s/^X//" >'Pnews.SH' <<'END_OF_FILE'
- case $CONFIG in
- X '') . ./config.sh ;;
- esac
- echo "Extracting Pnews (with variable substitutions)"
- X$spitshell >Pnews <<!GROK!THIS!
- X$startsh
- X# $Id: Pnews.SH,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
- X#
- X# $Log: Pnews.SH,v $
- X# Revision 4.4.2.1 1991/12/01 18:05:42 sob
- X# Patchlevel 2
- X#
- X# Revision 4.4 1991/09/09 20:18:23 sob
- X# release 4.4
- X#
- X#
- X#
- X# This software is Copyright 1991 by Stan Barber.
- X#
- X# Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X# use this software as long as: there is no monetary profit gained
- X# specifically from the use or reproduction of this software, it is not
- X# sold, rented, traded or otherwise marketed, and this copyright notice is
- X# included prominently in any copy made.
- X#
- X# The author make no claims as to the fitness or correctness of this software
- X# for any use whatsoever, and it is provided as is. Any use of this software
- X# is at the user's own risk.
- X#
- X# syntax: Pnews -h headerfile or
- X# Pnews -h headerfile oldarticle or
- X# Pnews newsgroup title or just
- X# Pnews
- X
- export PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh \$0; kill \$\$)
- X
- X# System dependencies
- X
- mailer="${mailer-/bin/mail}"
- X# if you change this to something that does signatures, take out signature code
- X
- case $portable in
- define)
- X# your site name
- case "$hostcmd" in
- X'') sitename="$sitename" ;;
- X*) sitename=\`$hostcmd\` ;;
- esac
- case \$sitename in
- X *.*)
- X ;;
- X *)
- X sitename=\${sitename}.$domain
- X ;;
- esac
- X# where recordings, distributions and moderators are kept
- lib=\`$filexp $lib\`
- X# where important rn things are kept
- rnlib=\`$filexp $rnlib\`
- X;;
- undef)
- X# your site name
- sitename="$sitename"
- X# where recordings, distributions and moderators are kept
- lib="$lib"
- X# where important rn things are kept
- rnlib="$rnlib"
- X;;
- esac
- X
- X# your organization name
- orgname="$orgname"
- X# what pager you use--if you have kernal paging use cat
- pager="\${PAGER-$pager}"
- X# how you derive full names, bsd, usg, or other
- nametype="$nametype"
- X# default editor
- defeditor="$defeditor"
- X# how not to echo with newline
- n="$n"
- c="$c"
- X
- X# You should also look at the distribution warnings below marked !DIST!
- X# to make sure any distribution regions you are a member of are included.
- X# The following are some prototypical distribution groups. If you do not
- X# use them all set the unused ones to a non-null string such as 'none'.
- loc="$locpref"
- org="$orgpref"
- city="$citypref"
- state="$statepref"
- cntry="$cntrypref"
- cont="$contpref"
- X
- test=${test-test}
- sed=${sed-sed}
- echo=${echo-echo}
- cat=${cat-cat}
- egrep=${egrep-egrep}
- grep=${grep-grep}
- rm=${rm-rm}
- tr=${tr-tr}
- inews=${inews-inews}
- nidump=${nidump}
- ypmatch=${ypmatch}
- X
- X!GROK!THIS!
- case "$ignoreorg" in
- define) $spitshell >>Pnews <<'!NO!SUBS!'
- orgname=${NEWSORG-$orgname}
- X!NO!SUBS!
- X ;;
- X*) $spitshell >>Pnews <<'!NO!SUBS!'
- orgname=${NEWSORG-${ORGANIZATION-$orgname}}
- X!NO!SUBS!
- X ;;
- esac
- X$spitshell >>Pnews <<'!NO!SUBS!'
- dotdir=${DOTDIR-${HOME-$LOGDIR}}
- tmpart=$dotdir/.article
- X
- if $test -f $dotdir/.pnewsexpert; then
- X expertise=expert
- else
- X $cat <<'EOM'
- I see you've never used this version of Pnews before. I will give you extra
- help this first time through, but then you must remember what you learned.
- If you don't understand any question, type h and a CR (carriage return) for
- help.
- X
- If you've never posted an article to the net before, it is HIGHLY recommended
- that you read the netiquette document found in news.announce.newusers so
- that you'll know to avoid the commonest blunders. To do that, interrupt
- Pnews, and get to the top-level prompt of rn. Type "g news.announce.newusers"
- and you are on your way.
- X
- XEOM
- X expertise=beginner
- fi
- X
- case $cntry in
- X can) stpr=Province ;;
- X *) stpr=State ;;
- esac
- X
- headerfile=""
- case $# in
- X0) ;;
- X*) case $1 in
- X -h)
- X headerfile="$2"
- X shift
- X shift
- X case $# in
- X 0)
- X oldart=""
- X ;;
- X *)
- X oldart="$1"
- X shift
- X ;;
- X esac
- X ;;
- X esac
- X ;;
- esac
- X
- case $headerfile in
- X'')
- X . $rnlib/Pnews.header
- X ;;
- X*)
- X $cat < $headerfile > $tmpart
- X ;;
- esac
- X rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $echo Article appended to ${HOME-$LOGDIR}/dead.article ; exit"
- X trap "$rescue" 1
- X trap "$rescue" 2
- X
- X$echo ""
- X
- X# extract the newsgroups list and distribution
- hdr_newsgroups=`$sed -n -e '/^Newsgroups:/{' -e 's///' -e 's/,/ /g' -e p -e q -e '}' $tmpart`
- hdr_distribution=`$sed -n -e '/^Distribution:/{' -e 's///' -e p -e q -e '}' $tmpart`
- X
- X# check for "poster" magic cookie
- flag=0
- for ng in $hdr_newsgroups ; do
- X case "$ng" in
- X poster) flag=1 ;;
- X *) ;;
- X esac
- done
- case $flag in
- X1)
- X $echo " "
- X $echo "The original author has requested that messages be sent back via"
- X $echo "mail rather than posting to news. Do you want to jump out of this"
- X $echo $n "and mail your reply instead? [yn] $c"
- X read ans
- X case $ans in
- X n*) ;;
- X *) exit ;;
- X esac
- X $echo " "
- X $echo "OK, but you will have to edit the 'Newsgroups:' line in the message."
- X ;;
- esac
- X
- X# play recorded message
- if $test -s ${lib}/recording ; then
- X for ng in $hdr_newsgroups ; do
- X _rec1=${lib}/`$sed -n "/^$ng/s/^.* //p" ${lib}/recording`
- X _tmp=`$echo $ng |$sed "s/\..*//"`
- X _rec2=${lib}/`$cat -s ${lib}/recording|$grep ${_tmp}.all|$sed "s/^.* //"`
- X if $test -f ${_rec1} ; then
- X $cat -s ${_rec1}
- X fi
- X if $test -f ${_rec2} ; then
- X $cat -s ${_rec2}
- X fi
- X done
- fi
- X
- X# determine the distribution of this message
- set X $hdr_distribution
- shift
- if $test $# -gt 0 ; then
- X dist=$1.whatever
- else
- X set X $hdr_newsgroups
- X shift
- X if $test $# -gt 0 ; then
- X dist=$1.whatever
- X else
- X dist=misc.whatever
- X fi
- fi
- case $dist in
- X*.*)
- X ;;
- X*)
- X dist=$dist.whatever
- X ;;
- esac
- X
- X# tell them what we think they are doing... !DIST!
- case $dist in
- world.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*)
- X $cat <<'EOM'
- This program posts news to thousands of machines throughout the entire
- civilized world. Your message will cost the net hundreds if not thousands of
- dollars to send everywhere. Please be sure you know what you are doing.
- X
- XEOM
- X ;;
- vmsnet.*)
- X $echo 'This program posts news to many machines.'
- X ;;
- bit.*)
- X $echo 'This program posts news to many machines on BITNET.'
- X ;;
- ddn.*)
- X $echo 'This program posts news to many machines throughout the internet.'
- X ;;
- X$cont.*)
- X $echo 'This program posts news to many machines throughout the continent.'
- X ;;
- X$cntry.*)
- X $echo 'This program posts news to many machines throughout the country.'
- X ;;
- X$state.*)
- X $echo 'This program posts news to many machines throughout the state.'
- X ;;
- X$city.*)
- X $echo 'This program posts news to many machines throughout the city.'
- X ;;
- X$org.*)
- X $echo 'This program posts news to machines throughout the organization.'
- X ;;
- X$loc.*)
- X $echo 'This program posts news to machines throughout the local organization.'
- X ;;
- X*.*)
- X $echo 'This program may post news to many machines.'
- X ;;
- to.*)
- X $echo 'This program may post news to a particular machine.'
- X ;;
- X*)
- X $echo 'This program posts news to everyone on the machine.'
- X ;;
- esac
- ans=""
- while $test "$ans" = "" ; do
- X $echo $n "Are you absolutely sure that you want to do this? [ny] $c"
- X read ans
- X case $ans in
- X y*) ;;
- X f*) ;;
- X h*) $cat <<'EOH'
- X
- Type n or CR to exit, y to post.
- X
- XEOH
- X ans="" ;;
- X *) exit ;;
- X esac
- done
- X
- file=h
- while $test "$file" = h ; do
- X $echo ""
- X $echo $n "Prepared file to include [none]: $c"
- X read file
- X case $file in
- X h)
- X $cat <<'EOH'
- X
- If you have already produced the body of your article, type the filename
- for it here. If you just want to proceed directly to the editor, type a
- RETURN. In any event, you will be allowed to edit as many times as you
- want before you send off the article.
- XEOH
- X ;;
- X '')
- X $echo "" >> $tmpart
- X state=edit
- X ;;
- X *)
- X $cat $file >>$tmpart
- X state=ask
- X ;;
- X esac
- done
- X
- X$echo ""
- X
- while true ; do
- X case $state in
- X edit)
- X case $expertise in
- X beginner)
- X $cat </dev/null >$dotdir/.pnewsexpert
- X $cat <<'EOMessage'
- A temporary file has been created for you to edit. Be sure to leave at
- least one blank line between the header and the body of your message.
- X(And until a certain bug is fixed all over the net, don't start the body of
- your message with any indentation, or it may get eaten.)
- X
- Within the header may be fields that you don't understand. If you don't
- understand a field (or even if you do), you can simply leave it blank, and
- it will go away when the article is posted.
- X
- Type return to get the default editor, or type the name of your favorite
- editor.
- X
- XEOMessage
- X ;;
- X esac
- X case "${VISUAL-${EDITOR-}}" in
- X '')
- X tmp=h
- X ;;
- X *)
- X tmp=''
- X ;;
- X esac
- X while $test "$tmp" = h ; do
- X $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c"
- X read tmp
- X case $tmp in
- X h)
- X $cat <<'EOH'
- X
- Type a return to get the default editor, or type the name of the editor you
- prefer. The default editor depends on the VISUAL and EDITOR environment
- variables.
- X
- XEOH
- X ;;
- X '')
- X ;;
- X *)
- X VISUAL=$tmp
- X export VISUAL
- X ;;
- X esac
- X done
- X trap : 2
- X ${VISUAL-${EDITOR-$defeditor}} $tmpart $oldart
- X trap "$rescue" 2
- X state=ask
- X ;;
- X
- X ask)
- X $echo ""
- X $echo $n "Send, abort, edit, or list? $c"
- X read ans
- X
- X case "$ans" in
- X a*)
- X state=rescue
- X ;;
- X e*)
- X set $ans
- X case $# in
- X 2) VISUAL="$2" ;;
- X esac
- X state=edit
- X ;;
- X l*)
- X $pager $tmpart
- X state=ask
- X ;;
- X s*)
- X state=send
- X ;;
- X h*)
- X $cat <<'EOH'
- X
- Type s to send the article, a to abort and append the article to dead.article,
- e to edit the article again, or l to list the article.
- X
- To invoke an alternate editor, type 'e editor'.
- XEOH
- X esac
- X ;;
- X
- X send)
- X set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
- X shift
- X case $# in
- X 2)
- X state=cleanup
- X if $test -f $lib/moderators; then
- X tryinews=no
- X shift
- X case "$1" in
- X *,*) set `$echo $1 | tr ',' ' '`;;
- X esac
- X for newsgroup in $*; do
- X# the following screwy sed should prevent Eunice from hanging on no match
- X moderator=`$sed <$lib/moderators \
- X -e "/^$newsgroup[ ]/!s/.*//" \
- X -e "s/^$newsgroup[ ]//"`
- X case ${moderator}X in
- X X) tryinews=yes
- X ;;
- X *)
- X $echo Mailing to moderator $moderator
- X case "$sign" in
- X n*) ;;
- X *)
- X if $test -f $dotdir/.signature; then
- X $echo $n "Append .signature file? [y] $c"
- X read ans
- X case $ans in
- X ''|y*)
- X $echo "-- " >> $tmpart
- X $cat $dotdir/.signature >> $tmpart
- X ;;
- X esac
- X fi
- X sign=no
- X ;;
- X esac
- X case "$mailer" in
- X *recmail)
- X $echo To: $moderator | $cat - $tmpart | $mailer
- X ;;
- X *)
- X $mailer $moderator < $tmpart
- X ;;
- X esac
- X case $? in
- X 0) ;;
- X *)
- X $echo Unable to mail to moderator $moderator
- X state=rescue
- X ;;
- X esac
- X ;;
- X esac
- X done
- X else
- X tryinews=yes
- X fi
- X case "$tryinews" in
- X yes)
- X if $sed '1,/^[ ]*$/{/^[A-Z][-A-Za-z0-9]*:[ ]*$/d;}' $tmpart |
- X $inews -h ; then
- X : null
- X else
- X state=rescue
- X fi
- X ;;
- X esac
- X ;;
- X *)
- X $echo ""
- X $echo "Malformed Newsgroups line."
- X $echo ""
- X sleep 1
- X state=edit
- X ;;
- X esac
- X ;;
- X rescue)
- X if $test -s $tmpart; then
- X $cat $tmpart >> ${HOME-$LOGDIR}/dead.article
- X $echo "Article appended to ${HOME-$LOGDIR}/dead.article"
- X $echo "A copy may be temporarily found in $tmpart"
- X else
- X $echo "Null article discarded."
- X fi
- X exit
- X ;;
- X cleanup)
- X case "${AUTHORCOPY-none}" in
- X none)
- X ;;
- X *)
- X set X ${USER-${LOGNAME-`who am i`}} unknown
- X shift
- X $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $AUTHORCOPY "From $1 `date`"
- X if $test $? -eq 0 ; then
- X $echo "Article appended to $AUTHORCOPY"
- X else
- X $echo "Cannot append to $AUTHORCOPY"
- X fi
- X ;;
- X esac
- X exit
- X ;;
- X esac
- done
- X!NO!SUBS!
- X$eunicefix Pnews
- chmod 755 Pnews
- X$spitshell >Pnews.header <<'!NO!SUBS!'
- case $# in
- X0)
- X ng=h
- X while $test "$ng" = h ; do
- X $echo ""
- X $echo $n "Newsgroup(s): $c"
- X read ng
- X case $ng in
- X h)
- X $cat <<'EOH'
- X
- Type the name of one or more newsgroups to which you wish to post an article.
- If you want to post to multiple newsgroups, it is better to do them all at
- once than to post to each newsgroup individually, which defeats the news
- reading programs' strategies of eliminating duplicates.
- X
- Separate multiple newsgroup names with commas.
- XEOH
- X ;;
- X esac
- X done
- X ;;
- X*)
- X ng=$1
- X shift
- X ;;
- esac
- case $ng in
- X*\ *)
- X ng=`$echo "$ng" | $sed 's/[, ] */,/g'`
- X ;;
- esac
- case $ng in
- bit.*|pubnet.*|bionet.*|vmsnet.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*)
- X defdist=world
- X dist=h
- X ;;
- ddn.*)
- X defdist=inet
- X dist=h
- X ;;
- to.*)
- X defdist=''
- X dist=''
- X ;;
- X*.*)
- X defdist=`expr "X$ng" : 'X\([a-z0-9]*\)'`
- X dist=h
- X ;;
- X*)
- X defdist=''
- X dist=''
- X ;;
- esac
- X
- while $test "$dist" = h ; do
- X if $test -f $lib/distributions; then
- X $echo " "
- X $echo "Your local distribution prefixes are:"
- X $cat $lib/distributions
- X $echo " "
- X else
- X $egrep -v '[ ]none$' <<EOM
- X
- Your local distribution prefixes are:
- X Local organization: $loc
- X Organization: $org
- X City: $city
- X $stpr: $state
- X Country: $cntry
- X Continent: $cont
- X Everywhere: world
- X
- XEOM
- X fi
- X $echo $n "Distribution ($defdist): $c"
- X read dist
- X case $dist in
- X '') dist=$defdist ;;
- X esac
- X case $dist in
- X h)
- X $cat <<'EOH'
- X
- The Distribution line may be used to limit the distribution of an article
- to some subset of the systems that would receive the article based only on
- the Newsgroups line. For example, if you want to sell your car in talk.auto,
- and you live in New Jersey, you might want to put "nj" on the Distribution
- line to avoid advertising in California, which has enough problems of its own.
- The actual area designators to use depend on where you are, of course.
- XEOH
- X ;;
- X ''|$loc*|$org*|$city*|$state*|$cntry*|$cont*|$defdist)
- X ;;
- X world*|comp*|news*|sci*|rec*|misc*|soc*|talk*|alt*)
- X dist=''
- X ;;
- X *)
- X if $test -f $lib/distributions && \
- X $egrep "^$dist[ ]" $lib/distributions >$tmpart && \
- X $test -s $tmpart; then
- X : null
- X else
- X $echo "Unrecognized distribution prefix--type h for help, CR to use anyway."
- X defdist=$dist
- X dist=h
- X fi
- X ;;
- X esac
- done
- X
- follow=""
- X
- X# LCP 16-Oct-91 Subject line is required. Make it a little more
- X# difficult to omit. Added "while : ; do", ... "done", and "if"
- X# at end of while loop.
- while :
- do
- X case $# in
- X 0)
- X title=h
- X while $test "$title" = h ; do
- X $echo ""
- X $echo $n "Title/Subject: $c"
- X read title
- X case $title in
- X h)
- X $cat <<'EOH'
- X
- Type the title for your article. Please make it as informative as possible
- X(within reason) so that people who aren't interested won't have to read the
- article to find out they aren't interested. This includes marking movie
- spoilers as (spoiler), and rotated jokes as (rot 13).
- XEOH
- X ;;
- X esac
- X done
- X ;;
- X *)
- X title="$*"
- X # LCP 16-Oct-91 Added "set" and "shift". Must insure $# is 0
- X # in case the title is all white space and we make another
- X # pass thru this loop.
- X set X
- X shift
- X ;;
- X esac
- X if expr "X$title" : "^X[ ]*$" > /dev/null 2>&1
- X then
- X $cat <<'EOH'
- X
- Articles without a "Subject:" line will not be accepted by the News
- system. Please give a Title/Subject line for your article.
- XEOH
- X else
- X break
- X fi
- done
- X
- X
- X# now build a file with a header for them to edit
- X
- set X ${USER-${LOGNAME-`who am i`}}
- shift
- logname=$1
- case $logname in
- X*!*) logname=`expr "$logname" : '!\(.*\)$'` ;;
- esac
- case ${NAME-$nametype} in
- bsd)
- X if $test "$ypmatch" != ""; then
- X fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/"`
- X elif $test "$nidump" != ""; then
- X fullname=`$nidump passwd / | $sed -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
- X fi
- X if $test "$fullname" = ""; then
- X fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
- X fi
- X case $fullname in
- X *'&'*) : GACK
- X lname=`$echo $logname | $tr 'a-z' 'A-Z'`
- X lname=`$echo $lname $logname | $sed 's/^\(.\)[^ ]* ./\1/'`
- X fullname=`$echo "$fullname" | $sed "s/&/${lname}/"`
- X ;;
- X esac
- X ;;
- usg)
- X if $test "$ypmatch" != ""; then
- X fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q"`
- X fi
- X if $test "$fullname" = ""; then
- X fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q" -e "}" -e "d"`
- X fi
- X ;;
- X*)
- X fullname=${NAME-`$cat $dotdir/.fullname`}
- X ;;
- esac
- X
- case $orgname in
- X/*) orgname=`$cat $orgname` ;;
- esac
- X
- X$sed -e '/^Reply-To: $/d' > $tmpart <<EOHeader
- Newsgroups: $ng
- Subject: $title
- Summary:
- Reply-To: $REPLYTO
- XFollowup-To: $follow
- Distribution: $dist
- Organization: $orgname
- Keywords:
- X
- XEOHeader
- X
- X!NO!SUBS!
- case "$isrrn" in
- define) sed < Pnews.header -e '/^#NORMAL/d' > Pnews.h.new ;;
- X*) sed < Pnews.header -e '/^#NORMAL/s/^#NORMAL//' > Pnews.h.new ;;
- esac
- mv Pnews.h.new Pnews.header
- X$eunicefix Pnews.header
- END_OF_FILE
- if test 17117 -ne `wc -c <'Pnews.SH'`; then
- echo shar: \"'Pnews.SH'\" unpacked with wrong size!
- fi
- # end of 'Pnews.SH'
- fi
- if test -f 'help.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'help.c'\"
- else
- echo shar: Extracting \"'help.c'\" \(16450 characters\)
- sed "s/^X//" >'help.c' <<'END_OF_FILE'
- X/* $Id: help.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
- X *
- X * $Log: help.c,v $
- X * Revision 4.4.2.1 1991/12/01 18:05:42 sob
- X * Patchlevel 2 changes
- X *
- X * Revision 4.4 1991/09/09 20:18:23 sob
- X * release 4.4
- X *
- X *
- X *
- X */
- X/* This software is Copyright 1991 by Stan Barber.
- X *
- X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X * use this software as long as: there is no monetary profit gained
- X * specifically from the use or reproduction of this software, it is not
- X * sold, rented, traded or otherwise marketed, and this copyright notice is
- X * included prominently in any copy made.
- X *
- X * The author make no claims as to the fitness or correctness of this software
- X * for any use whatsoever, and it is provided as is. Any use of this software
- X * is at the user's own risk.
- X */
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "rn.h"
- X#include "term.h"
- X#include "INTERN.h"
- X#include "help.h"
- X
- void
- help_init()
- X{
- X ;
- X}
- X
- int
- help_page()
- X{
- X int cmd;
- X
- X#ifdef PAGERHELP
- X doshell(sh,filexp(PAGERHELP));
- X#else
- X page_init();
- X if ((cmd = print_lines("\
- Paging commands:\n\
- X",STANDOUT)) ||
- X (cmd = print_lines("\n\
- SP Display the next page.\n\
- x Display the next page decrypted (rot13).\n\
- d Display half a page more.\n\
- CR Display one more line.\n\
- X^R,v,^X Restart the current article (v=verbose header, ^X=rot13).\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- b Back up one page.\n\
- X^L,X Refresh the screen (X=rot13).\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- t Display the entire article tree and all its subjects.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- g pat Go to (search forward within article for) pattern.\n\
- G Search again for current pattern within article.\n\
- X^G Search for next line beginning with \"Subject:\".\n\
- TAB Search for next line beginning with a different character.\n\
- q Quit the pager, go to end of article. Leave article read or unread.\n\
- j Junk this article (mark it read). Goes to end of article.\n\
- X\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- The following commands skip the rest of the current article, then behave\n\
- just as if typed to the 'What next?' prompt at the end of the article:\n\
- X",STANDOUT)) ||
- X (cmd = print_lines("\n\
- n Scan forward for next unread article.\n\
- N Go to next article.\n\
- X^N Scan forward for next unread article with same title.\n\
- p,P,^P Same as n,N,^N, only going backwards.\n\
- X- Go to previously displayed article.\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X<,> Browse the previous/next selected thread. If no threads are selected,\n\
- X all threads that had unread news upon entry to the group are considered\n\
- X selected for browsing. Entering an empty group browses all threads.\n\
- X[,],{,} Go to parent/child/root/leaf in thread.\n\
- X\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- The following commands also take you to the end of the article.\n\
- Type h at end of article for a description of these commands:\n\
- X",STANDOUT)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X # $ & / = ? c C f F k K ^K J , m M number e r R ^R s S u U v w W Y ^ |\n\
- X\n\
- X(To return to the middle of the article after one of these commands, type ^L.)\n\
- X",NOMARKING)) )
- X#else
- X (cmd = print_lines("\
- X # $ & / = ? c C f F k K ^K m M number e r R ^R s S u v w W Y ^ |\n\
- X\n\
- X(To return to the middle of the article after one of these commands, type ^L.)\n\
- X",NOMARKING)) )
- X#endif
- X return cmd;
- X#endif
- X return 0;
- X}
- X
- int
- help_art()
- X{
- X int cmd;
- X#ifdef ARTHELP
- X doshell(sh,filexp(ARTHELP));
- X#else
- X page_init();
- X if ((cmd = print_lines("\
- Article Selection commands:\n\
- X",STANDOUT)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\n\
- n,SP Find next unread article (follows discussion-tree in threaded groups).\n\
- X",NOMARKING)) ||
- X#else
- X (cmd = print_lines("\n\
- n,SP Scan forward for next unread article.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- N Go to next article.\n\
- X^N Scan forward for next unread article with same subject.\n\
- p,P,^P Same as n,N,^N, only going backwards.\n\
- X- Go to previously displayed article.\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X<,> Browse the previous/next selected thread. If no threads are selected,\n\
- X all threads that had unread news upon entry to the group are considered\n\
- X selected for browsing. Entering an empty group browses all threads.\n\
- X[,] Go to article's parent/child.\n\
- X{,} Go to tree's root/leaf.\n\
- t Display the entire article tree and all its subjects.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- number Go to specified article.\n\
- range{,range}:command{:command}\n\
- X Apply one or more commands to one or more ranges of articles.\n\
- X Ranges are of the form: number | number-number. You may use . for\n\
- X the current article, and $ for the last article.\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X Valid commands are: e, j, m, M, s, S, t, T, |, +, and -.\n\
- X:cmd Perform a command on all the selected articles.\n\
- X",NOMARKING)) ||
- X#else
- X (cmd = print_lines("\
- X Valid commands are: e, j, m, M, s, S, and |.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- X/pattern/modifiers\n\
- X Scan forward for article containing pattern in the subject line.\n\
- X (Use ?pat? to scan backwards; append h to scan headers, a to scan\n\
- X entire articles, r to scan read articles, c to make case sensitive.)\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X/pattern/modifiers:command{:command}\n\
- X Apply one or more commands to the set of articles matching pattern.\n\
- X Use a K modifier to save entire command to the KILL file for this\n\
- X newsgroup. Commands m and M, if first, imply an r modifier.\n\
- X Valid commands are the same as for the range command.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- f,F Submit a followup article (F = include this article).\n\
- r,R Reply through net mail (R = include this article).\n\
- e dir{|command}\n\
- X Extract to directory using /bin/sh, uudecode, unship, or command.\n\
- s ... Save to file or pipe via sh.\n\
- S ... Save via preferred shell.\n\
- w,W Like s and S but save without the header.\n\
- X| ... Same as s|...\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- C Cancel this article, if yours.\n\
- X^R,v Restart article (v=verbose).\n\
- X^X Restart article, rot13 mode.\n\
- c Catch up (mark all articles as read).\n\
- b Back up one page.\n\
- X^L Refresh the screen. You can get back to the pager with this.\n\
- XX Refresh screen in rot13 mode.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X^ Go to first unread article. Disables subject search mode.\n\
- X$ Go to end of newsgroup. Disables subject search mode.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("# Print last article number.\n\
- X& Print current values of command-line switches.\n\
- X&switch {switch}\n\
- X Set or unset more switches.\n\
- X&& Print current macro definitions.\n\
- X&&def Define a new macro.\n\
- j Junk this article (mark it read). Stays at end of article.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- m Mark article as still unread.\n\
- M Mark article as still unread upon exiting newsgroup or Y command.\n\
- Y Yank back articles marked temporarily read via M.\n\
- k Kill current subject (mark articles as read).\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X, Mark current article and its replies as read.\n\
- J Junk entire thread (mark all subjects as read in this thread).\n\
- T Trash current thread (like 'J'), and save command in KILL file.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- K Mark current subject as read, and save command in KILL file.\n\
- X^K Edit local KILL file (the one for this newsgroup).\n\
- X= List subjects of unread articles.\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X+ Enter thread selection mode.\n\
- U Unread some news -- prompts for thread, subthread, all, or select.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- u Unsubscribe from this newsgroup.\n\
- q Quit this newsgroup for now.\n\
- Q Quit newsgroup, staying at current newsgroup.\n\
- X",NOMARKING)) )
- X return cmd;
- X#endif
- X return 0;
- X}
- X
- int
- help_ng()
- X{
- X int cmd;
- X#ifdef NGHELP
- X doshell(sh,filexp(NGHELP));
- X#else
- X page_init();
- X if (cmd = print_lines("\
- Newsgroup Selection commands:\n\
- X",STANDOUT) )
- X return cmd;
- X if (ng != nextrcline) {
- X if ((cmd = print_lines("\
- X\n\
- y,SP Do this newsgroup now.\n\
- X.cmd Do this newsgroup, executing cmd as first command.\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- X+ Enter this newsgroup through the thread selector (like typing .+<CR>).\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- X= Start this newsgroup, but list subjects before reading articles.\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- U Enter this newsgroup by way of the \"Set unread?\" prompt.\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- u Unsubscribe from this newsgroup.\n\
- X",NOMARKING)) )
- X return cmd;
- X }
- X if ((cmd = print_lines("\
- c Catch up (mark this newsgroup all read).\n\
- A Abandon read/unread changes to this newsgroup since you started trn.\n\
- X\n\
- n Go to the next newsgroup with unread news.\n\
- N Go to the next newsgroup.\n\
- p Go to the previous newsgroup with unread news.\n\
- P Go to the previous newsgroup.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X- Go to the previously displayed newsgroup.\n\
- X1 Go to the first newsgroup.\n\
- X^ Go to the first newsgroup with unread news.\n\
- X$ Go to the last newsgroup.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- g name Go to the named newsgroup. Subscribe to new newsgroups this way too.\n\
- X/pat Search forward for newsgroup matching pattern.\n\
- X?pat Search backward for newsgroup matching pattern.\n\
- X (Use * and ? style patterns. Append r to include read newsgroups.)\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- l pat List unsubscribed newsgroups containing pattern.\n\
- m name Move named newsgroup elsewhere (no name moves current newsgroup).\n\
- o pat Only display newsgroups matching pattern. Omit pat to unrestrict.\n\
- a pat Like o, but also scans for unsubscribed newsgroups matching pattern.\n\
- L List current .newsrc.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X& Print current command-line switch settings.\n\
- X&switch {switch}\n\
- X Set (or unset) more command-line switches.\n\
- X&& Print current macro definitions.\n\
- X&&def Define a new macro.\n\
- X!cmd Shell escape.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- q Quit trn.\n\
- x Quit, restoring .newsrc to its state at startup of trn.\n\
- X^K Edit the global KILL file. Use commands like /pattern/j to suppress\n\
- X pattern in every newsgroup.\n\
- v Print version.\n\
- X",NOMARKING)) )
- X return cmd;
- X#endif
- X#ifdef PUSHBACK
- X if (cmd = get_anything())
- X return cmd;
- X show_macros();
- X#endif
- X return 0;
- X}
- X
- X#ifdef ESCSUBS
- int
- help_subs()
- X{
- X int cmd;
- X#ifdef SUBSHELP
- X doshell(sh,filexp(SUBSHELP));
- X#else
- X page_init();
- X if ((cmd = print_lines("\
- Valid substitutions are:\n\
- X",STANDOUT)) ||
- X (cmd = print_lines("\
- X\n\
- a Current article number\n\
- A Full name of current article (%P/%c/%a)\n\
- b Destination of last save command, often a mailbox\n\
- B Bytes to ignore at beginning of last saved article\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- c Current newsgroup, directory form\n\
- C Current newsgroup, dot form\n\
- d Full name of newsgroup directory (%P/%c)\n\
- D Distribution line from current article\n\
- e The last command executed to extract data from an article\n\
- XE The last extraction directory\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- f Who the current article is from\n\
- XF Newsgroups to followup to (from Newsgroups and Followup-To)\n\
- h (This help message)\n\
- H Host name (yours)\n\
- i Message-I.D. line from current article, with <>\n\
- I Reference indicator mark (see -F switch)\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- l News administrator's login name, if any\n\
- L Login name (yours)\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- m Current mode, first letter of (init,newsgroup,thread,article,pager,\n\
- X unread,Add,Catchup,Delete-bogus,Mailbox,Resubscribe)\n\
- X",NOMARKING)) ||
- X#else
- X (cmd = print_lines("\
- m Current mode, first letter of (init, newsgroup, article, pager,\n\
- X Add, Catchup, Delete bogus, Mailbox, Resubscribe)\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- M Number of article marked with M\n\
- n Newsgroups from current article\n\
- N Full name (yours)\n\
- o Organization (yours)\n\
- O Original working directory (where you ran trn from)\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- p Your private news directory (from -d)\n\
- P Public news spool directory\n\
- r Last reference (parent article id)\n\
- R References list for followup article\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- s Subject, with all Re's and (nf)'s stripped off\n\
- S Subject, with one Re stripped off\
- t New To line derived from From and Reply-To (Internet format)\n\
- T New To line derived from Path\n\
- u Number of unread articles\n\
- X",NOMARKING)) ||
- X#ifdef USETHREADS
- X (cmd = print_lines("\
- U Number of unread articles not counting the current article (when\n\
- X threads are selected, the count only reflects selected articles)\n\
- v The number of extra (unselected) articles, not counting the current\n\
- X one if it is unselected\n\
- w Mthreads' tmp directory\n\
- W Where thread files are saved\n\
- x News library directory\n\
- XX Trn library directory\n\
- z Length of current article in bytes\n\
- Z Number of selected threads\n\
- X",NOMARKING)) ||
- X#else
- X (cmd = print_lines("\
- U Number of unread articles not counting the current article\n\
- x News library directory\n\
- XX Trn library directory\n\
- z Length of current article in bytes\n\
- X",NOMARKING)) ||
- X#endif
- X (cmd = print_lines("\
- X~ Your home directory\n\
- X. Directory containing . files\n\
- X# A counter in multi-article saves\n\
- X$ Current process number\n\
- X/ Last search string\n\
- XESC Run preceding command through % interpretation\n\
- X",NOMARKING)) )
- X return cmd;
- X#endif
- X return 0;
- X}
- X#endif
- X
- X#ifdef USETHREADS
- int
- help_select()
- X{
- X int cmd;
- X
- X page_init();
- X if ((cmd = print_lines("\
- Thread selection commands:\n\
- X",STANDOUT)) ||
- X (cmd = print_lines("\n\
- a-z,0-9 Select/deselect the discussion thread by its letter or number. By\n\
- X default the letters h, k, m, n, p, q and y are omitted.\n\
- SP Perform the default command (usually > or Z).\n\
- CR Start reading. Selects the current thread if none are selected.\n\
- Z,TAB Start reading. If no articles are selected, read everything.\n\
- y, '.' Toggle the current thread's selection.\n\
- k, ',' Mark the current thread as killed.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- m, \\ Unmark the current thread.\n\
- X- Set a range, as in 2 - 5. Repeats the last marking action.\n\
- X@ Toggle all visible thread selections.\n\
- n, ] Move down to the next thread.\n\
- p, [ Move up to the previous thread.\n\
- X<, > Go to previous/next page.\n\
- X^, $ Go to first/last page.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- XX Mark all unselected articles as read and start reading.\n\
- D Mark unselected articles on the current page as read. Start\n\
- X reading if articles were selected, else go to next page.\n\
- J Junk all selected articles (mark them as read).\n\
- X^K Edit local KILL file (the one for this newsgroup).\n\
- X:cmd Perform a command on all the selected articles.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X/pattern/modifiers\n\
- X Scan all articles for a subject containing pattern.\n\
- X (Append h to scan headers, a to scan entire articles, c to make case\n\
- X sensitive, r to scan read articles (assumed when you are selecting\n\
- X read articles to set unread.)\n\
- X/pattern/modifiers:command{:command}\n\
- X Apply one or more commands to the set of articles matching pattern.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X Use a K modifier to save entire command to the KILL file for this\n\
- X newsgroup. Commands m and M, if first, imply an r modifier.\n\
- X Valid commands are: e, E, j, m, M, s, S, t, T, !, =, ',' and the\n\
- X thread selection commands: + and -.\n\
- N Leave this group as-is and go on to the next.\n\
- U Switch between selecting read/unread articles.\n\
- L Switch the current display mode between a terse mode without\n\
- X authors and a short and long mode with authors.\n\
- X",NOMARKING)) ||
- X (cmd = print_lines("\
- X& View or set command line switches.\n\
- X&& View or set macro definitions.\n\
- X!cmd Escape to a subshell.\n\
- q Quit selection mode.\n\
- Q Quit group and return to news group selection prompt for this group.\n\
- X",NOMARKING)) )
- X return cmd;
- X return 0;
- X}
- X#endif
- END_OF_FILE
- if test 16450 -ne `wc -c <'help.c'`; then
- echo shar: \"'help.c'\" unpacked with wrong size!
- fi
- # end of 'help.c'
- fi
- if test -f 'mt-read.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mt-read.c'\"
- else
- echo shar: Extracting \"'mt-read.c'\" \(15542 characters\)
- sed "s/^X//" >'mt-read.c' <<'END_OF_FILE'
- X/* $Id: mt-read.c,v 4.4.3.1 1991/11/22 04:12:15 davison Trn $
- X**
- X** $Log: mt-read.c,v $
- X** Revision 4.4.3.1 1991/11/22 04:12:15 davison
- X** Trn Release 2.0
- X**
- X*/
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "threads.h"
- X#include "mthreads.h"
- X
- extern char *lib, *rnlib, *mtlib, *spool, *threaddir, *homedir;
- extern long first;
- X
- static FILE *fp_in;
- X
- void tweak_roots ANSI((void));
- void wrap_it_up ANSI((int));
- X
- X/* Attempt to open the thread file. If it's there, only grab the totals
- X** from the start of the file. This should give them enough information
- X** to decide if they need to read the whole thing into memory.
- X*/
- int
- init_data(filename)
- char *filename;
- X{
- X root_root = Null(ROOT*);
- X author_root = Null(AUTHOR*);
- X unk_domain.ids = Nullart;
- X unk_domain.link = Null(DOMAIN*);
- X
- X if (filename && (fp_in = fopen(filename, FOPEN_RB)) != Nullfp) {
- X#ifdef SETBUFFER
- X setbuffer(fp_in, rwbuf, RWBUFSIZ);
- X#else
- X# ifdef SETVBUF
- X setvbuf(fp_in, rwbuf, _IOFBF, RWBUFSIZ);
- X# endif
- X#endif
- X if (fread((char*)&total,1,sizeof (TOTAL),fp_in) == sizeof (TOTAL)) {
- X#ifdef TMPTHREAD
- X lp_bmap(&total.first, 4);
- X wp_bmap(&total.root, 5);
- X#endif
- X
- X /* If the data looks ok, return success. */
- X if (total.last - total.first >= 0 && total.author > 0
- X && total.article > 0 && total.subject > 0 && total.domain > 0
- X && total.subject <= total.article && total.author <= total.article
- X && total.root <= total.article && total.domain <= total.article
- X && total.string1 > 0 && total.string2 > 0) {
- X return 1;
- X }
- X }
- X bzero(&total, sizeof (TOTAL));
- X total.first = first;
- X total.last = first - 1;
- X return 1;
- X }
- X bzero(&total, sizeof (TOTAL));
- X return 0;
- X}
- X
- X/* They want everything. Read in the packed information and transform it
- X** into a set of linked structures that is easily manipulated.
- X*/
- int
- read_data()
- X{
- X /* If this is an empty thread file, simply return success. */
- X if (!total.root) {
- X fclose(fp_in);
- X return 1;
- X }
- X
- X if (read_authors()
- X && read_subjects()
- X && read_roots()
- X && read_articles()
- X && read_ids())
- X {
- X tweak_roots();
- X fclose(fp_in);
- X return 1;
- X }
- X /* Something failed. Safefree takes care of checking if some items
- X ** were already freed. Any partially-allocated structures were freed
- X ** before we got here. All other structures are cleaned up.
- X */
- X if (root_root) {
- X register ROOT *root, *next_root;
- X register SUBJECT *subj, *next_subj;
- X
- X for (root = root_root; root; root = next_root) {
- X for (subj = root->subjects; subj; subj = next_subj) {
- X next_subj = subj->link;
- X free(subj->str);
- X free(subj);
- X }
- X next_root = root->link;
- X free(root);
- X }
- X root_root = Null(ROOT*);
- X }
- X if (author_array) {
- X register int count;
- X
- X for (count = total.author; count--;) {
- X free(author_array[count]->name);
- X free(author_array[count]);
- X }
- X safefree(&author_array);
- X author_root = Null(AUTHOR*);
- X }
- X if (article_array) {
- X register int count;
- X
- X for (count = total.article; count--;) {
- X free(article_array[count]);
- X }
- X safefree(&article_array);
- X }
- X safefree(&strings);
- X safefree(&subject_cnts);
- X safefree(&subject_array);
- X safefree(&author_cnts);
- X safefree(&root_array);
- X safefree(&ids);
- X unk_domain.ids = Nullart;
- X unk_domain.link = Null(DOMAIN*);
- X fclose(fp_in);
- X return 0;
- X}
- X
- X/* They don't want to read the data. Close the file if we opened it.
- X*/
- void
- dont_read_data(open_flag)
- int open_flag; /* 0 == not opened, 1 == open failed, 2 == open */
- X{
- X if (open_flag == 2) {
- X fclose(fp_in);
- X bzero(&total, sizeof (TOTAL));
- X }
- X}
- X
- X#define give_string_to(dest) /* Comment for makedepend to \
- X ** ignore the backslash above */ \
- X{\
- X register MEM_SIZE len = strlen(string_ptr) + 1;\
- X dest = safemalloc(len);\
- X bcopy(string_ptr, dest, (int)len);\
- X string_ptr += len;\
- X}
- X
- char *subject_strings, *string_end;
- X
- X/* The author information is an array of use-counts, followed by all the
- X** null-terminated strings crammed together. The subject strings are read
- X** in at the same time, since they are appended to the end of the author
- X** strings.
- X*/
- int
- read_authors()
- X{
- X register int count, author_tally;
- X register char *string_ptr;
- X register WORD *authp;
- X register AUTHOR *author, *last_author, **author_ptr;
- X
- X if (!read_item(&author_cnts, (MEM_SIZE)total.author * sizeof (WORD))
- X || !read_item(&strings, total.string1)) {
- X /* (Error already logged.) */
- X return 0;
- X }
- X#ifdef TMPTHREAD
- X wp_bmap(author_cnts, total.author);
- X#endif
- X
- X string_ptr = strings;
- X string_end = string_ptr + total.string1;
- X if (string_end[-1] != '\0') {
- X log_error("first string table is invalid.\n");
- X return 0;
- X }
- X
- X /* We'll use this array to point each article at its proper author
- X ** (packed values are saved as indexes).
- X */
- X author_array = (AUTHOR**)safemalloc(total.author * sizeof (AUTHOR*));
- X author_ptr = author_array;
- X
- X authp = author_cnts;
- X
- X author_tally = 0;
- X#ifndef lint
- X last_author = (AUTHOR*)&author_root;
- X#else
- X last_author = Null(AUTHOR*);
- X#endif
- X for (count = total.author; count; count--) {
- X if (string_ptr >= string_end) {
- X break;
- X }
- X *author_ptr++ = author = (AUTHOR*)safemalloc(sizeof (AUTHOR));
- X last_author->link = author;
- X give_string_to(author->name);
- X author_tally += *authp;
- X author->count = *authp++;
- X last_author = author;
- X }
- X last_author->link = Null(AUTHOR*);
- X
- X subject_strings = string_ptr;
- X
- X safefree(&author_cnts);
- X
- X if (count || author_tally > total.article) {
- X log_error("author unpacking failed.\n");
- X for (; count < total.author; count++) {
- X free((*--author_ptr)->name);
- X free(*author_ptr);
- X }
- X safefree(&author_array);
- X return 0;
- X }
- X return 1;
- X}
- X
- X/* The subject values consist of the crammed-together null-terminated strings
- X** (already read in above) and the use-count array. They were saved in the
- X** order that the roots require while being unpacked.
- X*/
- int
- read_subjects()
- X{
- X if (!read_item(&subject_cnts, (MEM_SIZE)total.subject * sizeof (WORD))) {
- X /* (Error already logged.) */
- X return 0;
- X }
- X#ifdef TMPTHREAD
- X wp_bmap(subject_cnts, total.subject);
- X#endif
- X return 1;
- X}
- X
- X/* Read in the packed root structures and recreate the linked list versions,
- X** processing each root's subjects as we go. Defer interpretation of article
- X** offsets until we unpack the article structures.
- X*/
- int
- read_roots()
- X{
- X register int count, subj_tally;
- X register char *string_ptr;
- X register WORD *subjp;
- X ROOT *root, *last_root, **root_ptr;
- X SUBJECT *subject, *last_subject, **subj_ptr;
- X int ret;
- X
- X /* Use this array when unpacking the article's subject offset. */
- X subject_array = (SUBJECT**)safemalloc(total.subject * sizeof (SUBJECT*));
- X subj_ptr = subject_array;
- X /* And this array points the article's root offset at the right spot. */
- X root_array = (ROOT**)safemalloc(total.root * sizeof (ROOT*));
- X root_ptr = root_array;
- X
- X subjp = subject_cnts;
- X string_ptr = subject_strings; /* string_end is already set */
- X
- X subj_tally = 0;
- X#ifndef lint
- X last_root = (ROOT*)&root_root;
- X#else
- X last_root = Null(ROOT*);
- X#endif
- X for (count = total.root; count--;) {
- X ret = fread((char*)&p_root, 1, sizeof (PACKED_ROOT), fp_in);
- X if (ret != sizeof (PACKED_ROOT)) {
- X log_error("failed root read -- %d bytes instead of %d.\n",
- X ret, sizeof (PACKED_ROOT));
- X return 0;
- X }
- X#ifdef TMPTHREAD
- X lp_bmap(&p_root.root_num, 1);
- X wp_bmap(&p_root.articles, 3);
- X#endif
- X if (p_root.articles < 0 || p_root.articles >= total.article
- X || subj_ptr - subject_array + p_root.subject_cnt > total.subject) {
- X log_error("root has invalid values.\n");
- X return 0;
- X }
- X *root_ptr++ = root = (ROOT*)safemalloc(sizeof (ROOT));
- X root->link = Null(ROOT*);
- X root->articles = Nullart;
- X root->seq = p_root.articles;
- X root->root_num = p_root.root_num;
- X root->thread_cnt = p_root.thread_cnt;
- X root->subject_cnt = p_root.subject_cnt;
- X last_root->link = root;
- X last_root = root;
- X
- X#ifndef lint
- X last_subject = (SUBJECT*)&root->subjects;
- X#else
- X last_subject = Null(SUBJECT*);
- X#endif
- X while (p_root.subject_cnt--) {
- X if (string_ptr >= string_end) {
- X log_error("error unpacking subject strings.\n");
- X last_subject->link = Null(SUBJECT*);
- X return 0;
- X }
- X *subj_ptr++ = subject = (SUBJECT*)safemalloc(sizeof (SUBJECT));
- X last_subject->link = subject;
- X give_string_to(subject->str);
- X subj_tally += *subjp;
- X subject->count = *subjp++;
- X last_subject = subject;
- X }
- X last_subject->link = Null(SUBJECT*);
- X }
- X if (subj_ptr != subject_array + total.subject
- X || subj_tally > total.article
- X || string_ptr != string_end) {
- X log_error("subject data is invalid.\n");
- X return 0;
- X }
- X safefree(&subject_cnts);
- X safefree(&strings);
- X
- X return 1;
- X}
- X
- bool invalid_data;
- X
- X/* A simple routine that checks the validity of the article's subject value.
- X** A -1 means that it is NULL, otherwise it should be an offset into the
- X** subject array we just unpacked.
- X*/
- SUBJECT *
- valid_subject(num, art_num)
- WORD num;
- long art_num;
- X{
- X if (num == -1) {
- X return Null(SUBJECT*);
- X }
- X if (num < 0 || num >= total.subject) {
- X log_error("invalid subject in thread file: %d [%ld]\n", num, art_num);
- X invalid_data = TRUE;
- X return Null(SUBJECT*);
- X }
- X return subject_array[num];
- X}
- X
- X/* Ditto for author checking. */
- AUTHOR *
- valid_author(num, art_num)
- WORD num;
- long art_num;
- X{
- X if (num == -1) {
- X return Null(AUTHOR*);
- X }
- X if (num < 0 || num >= total.author) {
- X log_error("invalid author in thread file: %d [%ld]\n", num, art_num);
- X invalid_data = TRUE;
- X return Null(AUTHOR*);
- X }
- X return author_array[num];
- X}
- X
- X/* Our parent/sibling information is a relative offset in the article array.
- X** zero for none. Child values are always found in the very next array
- X** element if child_cnt is non-zero.
- X*/
- ARTICLE *
- valid_node(relative_offset, num)
- WORD relative_offset;
- int num;
- X{
- X if (!relative_offset) {
- X return Nullart;
- X }
- X num += relative_offset;
- X if (num < 0 || num >= total.article) {
- X log_error("invalid node offset in thread file.\n");
- X invalid_data = TRUE;
- X return Nullart;
- X }
- X return article_array[num];
- X}
- X
- X/* Read the articles into their linked lists. Point everything everywhere. */
- int
- read_articles()
- X{
- X register int count;
- X register ARTICLE *article, **article_ptr;
- X int ret;
- X
- X /* Build an array to interpret interlinkages of articles. */
- X article_array = (ARTICLE**)safemalloc(total.article * sizeof (ARTICLE*));
- X article_ptr = article_array;
- X
- X /* Allocate all the structures up-front so that we can point to unread
- X ** siblings as we go.
- X */
- X for (count = total.article; count--;) {
- X *article_ptr++ = (ARTICLE*)safemalloc(sizeof (ARTICLE));
- X }
- X invalid_data = FALSE;
- X article_ptr = article_array;
- X for (count = 0; count < total.article; count++) {
- X ret = fread((char*)&p_article, 1, sizeof (PACKED_ARTICLE), fp_in);
- X if (ret != sizeof (PACKED_ARTICLE)) {
- X log_error("failed article read -- %d bytes instead of %d.\n", ret, sizeof (PACKED_ARTICLE));
- X return 0;
- X }
- X#ifdef TMPTHREAD
- X lp_bmap(&p_article.num, 2);
- X wp_bmap(&p_article.subject, 8);
- X#endif
- X
- X article = *article_ptr++;
- X article->num = p_article.num;
- X article->date = p_article.date;
- X article->subject = valid_subject(p_article.subject, p_article.num);
- X article->author = valid_author(p_article.author, p_article.num);
- X article->flags = p_article.flags;
- X article->child_cnt = p_article.child_cnt;
- X article->parent = valid_node(p_article.parent, count);
- X article->children = valid_node(article->child_cnt ? 1 : 0, count);
- X article->siblings = valid_node(p_article.siblings, count);
- X if (p_article.root < 0 || p_article.root >= total.root) {
- X log_error("invalid root offset in thread file.\n");
- X return 0;
- X }
- X article->root = root_array[p_article.root];
- X if (invalid_data) {
- X /* (Error already logged.) */
- X return 0;
- X }
- X }
- X
- X /* We're done with most of the pointer arrays. */
- X safefree(&root_array);
- X safefree(&subject_array);
- X
- X return 1;
- X}
- X
- X/* Read the message-id strings and attach them to each article. The data
- X** format consists of the mushed-together null-terminated strings (a domain
- X** name followed by all its unique-id prefixes) and then the article offsets
- X** to which they belong. The first domain name was omitted, as it is the
- X** ".unknown." domain for those truly weird message-id's without '@'s.
- X*/
- int
- read_ids()
- X{
- X register DOMAIN *domain, *last;
- X register ARTICLE *article;
- X register char *string_ptr;
- X register int i, count;
- X
- X if (!read_item(&strings, total.string2)
- X || !read_item(&ids,
- X (MEM_SIZE)(total.article+total.domain+1) * sizeof (WORD))) {
- X return 0;
- X }
- X#ifdef TMPTHREAD
- X wp_bmap(ids, total.article + total.domain + 1);
- X#endif
- X
- X string_ptr = strings;
- X string_end = string_ptr + total.string2;
- X
- X if (string_end[-1] != '\0') {
- X log_error("second string table is invalid.\n");
- X return 0;
- X }
- X
- X last = &unk_domain;
- X for (i = 0, count = total.domain + 1; count--; i++) {
- X if (i) {
- X if (string_ptr >= string_end) {
- X log_error("error unpacking domain strings.\n");
- X free_partial:
- X last->link = Null(DOMAIN*);
- X article = unk_domain.ids;
- X while (article) {
- X safefree(article->id);
- X article = article->id_link;
- X }
- X domain = unk_domain.link;
- X while (domain) {
- X free(domain->name);
- X article = domain->ids;
- X while (article) {
- X safefree(article->id);
- X article = article->id_link;
- X }
- X last = domain;
- X domain = domain->link;
- X free(last);
- X }
- X return 0;
- X }
- X domain = (DOMAIN*)safemalloc(sizeof (DOMAIN));
- X give_string_to(domain->name);
- X last->link = domain;
- X } else {
- X domain = &unk_domain;
- X }
- X if (ids[i] == -1) {
- X domain->ids = Nullart;
- X } else {
- X if (ids[i] < 0 || ids[i] >= total.article) {
- X id_error:
- X log_error("error in id array.\n");
- X domain->ids = Nullart;
- X goto free_partial;
- X }
- X article = article_array[ids[i]];
- X domain->ids = article;
- X for (;;) {
- X if (string_ptr >= string_end) {
- X log_error("error unpacking domain strings.\n");
- X article->id = Nullch;
- X article->id_link = Nullart;
- X goto free_partial;
- X }
- X give_string_to(article->id);
- X article->domain = domain;
- X if (++i >= total.article + total.domain + !count) {
- X log_error("overran id array unpacking domains.\n");
- X article->id_link = Nullart;
- X goto free_partial;
- X }
- X if (ids[i] != -1) {
- X if (ids[i] < 0 || ids[i] >= total.article) {
- X goto id_error;
- X }
- X article = article->id_link = article_array[ids[i]];
- X } else {
- X article->id_link = Nullart;
- X break;
- X }
- X }
- X }
- X last = domain;
- X }
- X last->link = Null(DOMAIN*);
- X safefree(&ids);
- X safefree(&strings);
- X
- X return 1;
- X}
- X
- X/* And finally, point all the roots at their root articles and get rid
- X** of anything left over that was used to aid our unpacking.
- X*/
- void
- tweak_roots()
- X{
- X register ROOT *root;
- X
- X for (root = root_root; root; root = root->link) {
- X root->articles = article_array[root->seq];
- X }
- X safefree(&author_array);
- X safefree(&article_array);
- X}
- X
- X/* A shorthand for reading a chunk of the file into a malloc'ed array.
- X*/
- int
- read_item(dest, len)
- char **dest;
- MEM_SIZE len;
- X{
- X int ret;
- X
- X *dest = safemalloc(len);
- X ret = fread(*dest, 1, (int)len, fp_in);
- X if (ret != len) {
- X log_error("only read %ld bytes instead of %ld.\n",
- X (long)ret, (long)len);
- X free(*dest);
- X *dest = Nullch;
- X return 0;
- X }
- X return 1;
- X}
- END_OF_FILE
- if test 15542 -ne `wc -c <'mt-read.c'`; then
- echo shar: \"'mt-read.c'\" unpacked with wrong size!
- fi
- # end of 'mt-read.c'
- fi
- if test -f 'rn.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rn.c'\"
- else
- echo shar: Extracting \"'rn.c'\" \(15991 characters\)
- sed "s/^X//" >'rn.c' <<'END_OF_FILE'
- X/* rn -- new readnews program
- X *
- X * Original Author: lwall@sdcrdcf.UUCP (Larry Wall)
- X * Organization: System Development Corporation, Santa Monica
- X * Current Author/Maintainer: sob@bcm.tmc.edu (Stan Barber)
- X * Organization: Baylor College of Medicine, Houston,Tx
- X *
- X * begun: 01/14/83
- X * 1.0: 04/08/83
- X * 2.0: 09/01/83
- X * RRN/RN: 11/01/89
- X * 4.4 07/04/91
- X */
- X/* This software is Copyright 1991 by Stan Barber.
- X *
- X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X * use this software as long as: there is no monetary profit gained
- X * specifically from the use or reproduction of this software, it is not
- X * sold, rented, traded or otherwise marketed, and this copyright notice is
- X * included prominently in any copy made.
- X *
- X * The author make no claims as to the fitness or correctness of this software
- X * for any use whatsoever, and it is provided as is. Any use of this software
- X * is at the user's own risk.
- X */
- X
- static char rnid[] = "@(#)$Id: rn.c,v 4.4.3.1 1991/11/22 04:12:14 davison Trn $";
- static char patchlevel[] = "Trn 2.1 based on rn 4.4 pl 2";
- X
- X/* $Log: rn.c,v $
- X * Revision 4.4.2.1 1991/12/01 18:05:42 sob
- X * Patchlevel 2 changes
- X *
- X * Revision 4.4.1.1 1991/09/25 19:38:08 sob
- X * Updated patchlevel message
- X *
- X * Revision 4.4 1991/09/09 20:27:37 sob
- X * release 4.4
- X *
- X *
- X *
- X *
- X */
- X
- X#include "INTERN.h"
- X#include "common.h"
- X#include "rn.h"
- X#ifdef SERVER
- X#include "server.h"
- X#endif
- X#include "EXTERN.h"
- X#include "rcstuff.h"
- X#include "term.h"
- X#include "final.h"
- X#include "search.h"
- X#include "ngdata.h"
- X#include "util.h"
- X#include "only.h"
- X#include "ngsrch.h"
- X#include "help.h"
- X#include "last.h"
- X#include "init.h"
- X#include "intrp.h"
- X#include "rcln.h"
- X#include "sw.h"
- X#include "addng.h"
- X#include "ng.h"
- X
- void
- rn_init()
- X{
- X ;
- X}
- X
- void
- main(argc,argv)
- int argc;
- char *argv[];
- X{
- X bool foundany;
- X register char *s;
- X bool oh_for_the_good_old_days = FALSE;
- X int direction = 1;
- X
- X#if defined(USETHREADS) && !THREAD_INIT
- X /* Default to threaded operation if our name starts with a 't' */
- X if ((s = rindex(argv[0],'/')) == Nullch)
- X s = argv[0];
- X else
- X s++;
- X if (*s == 't')
- X use_threads = TRUE;
- X#endif
- X foundany = initialize(argc,argv);
- X
- X if (maxngtodo)
- X starthere = 0;
- X else if (!foundany) { /* nothing to do? */
- X#ifdef VERBOSE
- X if (verbose)
- X fputs("\
- No unread news in subscribed-to newsgroups. To subscribe to a new\n\
- newsgroup use the g<newsgroup> command.\n\
- X",stdout) FLUSH;
- X#endif
- X starthere = nextrcline;
- X }
- X
- X /* loop through all unread news */
- X
- X {
- X bool special = FALSE; /* temporarily allow newsgroup */
- X /* with no unread news? */
- X bool retry; /* cycle back to top of list? */
- X NG_NUM recent_ng = 0;
- X
- X current_ng = 0;
- X do {
- X retry = FALSE;
- X if (findlast) {
- X findlast = FALSE;
- X starthere = 0;
- X if (*lastngname) {
- X if ((ng = find_ng(lastngname)) == nextrcline)
- X ng = 0;
- X else {
- X set_ngname(lastngname);
- X set_toread(ng);
- X if (toread[ng] <= TR_NONE)
- X ng = 0;
- X }
- X }
- X }
- X else {
- X ng = starthere;
- X starthere = 0;
- X }
- X while (ng <= nextrcline) { /* for each newsgroup */
- X mode = 'n';
- X if (ng >= nextrcline) { /* after the last newsgroup? */
- X ng = nextrcline; /* force it to 1 after */
- X#ifdef ONLY
- X if (maxngtodo) {
- X if (retry)
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\nRestriction %s%s still in effect.\n",
- X ngtodo[0],
- X maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
- X#endif
- X else {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\nNo articles under restriction.",
- X stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNo \"only\" articles.",stdout) FLUSH;
- X#endif
- X end_only(); /* release the restriction */
- X retry = TRUE;
- X }
- X }
- X#endif
- X }
- X else {
- X bool shoe_fits; /* newsgroup matches restriction? */
- X
- X if (toread[ng] >= TR_NONE) { /* recalc toread? */
- X set_ngname(rcline[ng]);
- X shoe_fits = inlist(ngname);
- X if (shoe_fits)
- X set_toread(ng);
- X if (paranoid) {
- X recent_ng = current_ng;
- X current_ng = ng;
- X cleanup_rc();
- X /* this may move newsgroups around */
- X ng = current_ng;
- X set_ngname(rcline[ng]);
- X }
- X }
- X if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE)
- X || !shoe_fits) { /* unwanted newsgroup? */
- X ng += direction; /* then skip it */
- X if (ng < 0) {
- X ng = 1;
- X direction = 1;
- X }
- X continue;
- X }
- X }
- X special = FALSE; /* go back to normal mode */
- X if (ng != current_ng) {
- X recent_ng = current_ng;
- X /* remember previous newsgroup */
- X current_ng = ng; /* remember current newsgroup */
- X }
- X reask_newsgroup:
- X unflush_output(); /* disable any ^O in effect */
- X if (ng >= nextrcline) {
- X dfltcmd = (retry ? "npq" : "qnp");
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n******** End of newsgroups--what next? [%s] ",
- X dfltcmd);
- X ELSE
- X#endif
- X#ifdef TERSE
- X printf("\n**** End--next? [%s] ", dfltcmd);
- X#endif
- X } else {
- X#ifdef USETHREADS
- X ThreadedGroup = (use_threads
- X && (thread_always || rcchar[ng] == '0'));
- X dfltcmd = (use_threads && select_on
- X && (ART_NUM)toread[ng] >= select_on ? "+ynq" : "ynq");
- X#else
- X dfltcmd = "ynq";
- X#endif
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n******** %3ld unread article%s in %s--read now? [%s] ",
- X (long)toread[ng], (toread[ng]==TR_ONE ? nullstr : "s"),
- X ngname, dfltcmd);
- X ELSE
- X#endif
- X#ifdef TERSE
- X printf("\n**** %3ld in %s--read? [%s] ",
- X (long)toread[ng],
- X ngname,dfltcmd);
- X#endif
- X }
- X fflush(stdout);
- X reinp_newsgroup:
- X eat_typeahead();
- X getcmd(buf);
- X if (errno || *buf == '\f') {
- X putchar('\n') FLUSH; /* if return from stop signal */
- X goto reask_newsgroup; /* give them a prompt again */
- X }
- X setdef(buf,dfltcmd);
- X#ifdef VERIFY
- X printcmd();
- X#endif
- X do_command:
- X direction = 1; /* default to forward motion */
- X switch (*buf) {
- X case 'P': /* goto previous newsgroup */
- X special = TRUE; /* don't skip it if toread==0 */
- X /* FALL THROUGH */
- X case 'p': /* find previous unread newsgroup */
- X if (ng > 0)
- X ng--;
- X direction = -1; /* go backward in the newsrc */
- X break;
- X case '-':
- X ng = recent_ng; /* recall previous newsgroup */
- X if (ng < nextrcline)
- X if (!get_ng(rcline[ng],FALSE))
- X ng = current_ng;
- X special = TRUE; /* don't skip it if toread==0 */
- X break;
- X case 'q': case 'Q': case 'x': /* quit? */
- X oh_for_the_good_old_days = (*buf == 'x');
- X putchar('\n') FLUSH;
- X ng = nextrcline+1; /* satisfy */
- X retry = FALSE; /* loop conditions */
- X break;
- X case '^':
- X putchar('\n') FLUSH;
- X ng = 0;
- X break;
- X case 'n': /* find next unread newsgroup */
- X if (ng == nextrcline) {
- X putchar('\n') FLUSH;
- X retry = TRUE;
- X }
- X else if (toread[ng] > TR_NONE)
- X retry = TRUE;
- X ng++;
- X break;
- X case 'N': /* goto next newsgroup */
- X special = TRUE; /* and don't skip it if toread==0 */
- X ng++;
- X break;
- X case '1': /* goto 1st newsgroup */
- X ng = 0;
- X special = TRUE; /* and don't skip it if toread==0 */
- X break;
- X case '$':
- X ng = nextrcline; /* goto last newsgroup */
- X retry = TRUE;
- X break;
- X case 'L':
- X list_newsgroups();
- X goto reask_newsgroup;
- X case '/': case '?': /* scan for newsgroup pattern */
- X#ifdef NGSEARCH
- X switch (ng_search(buf,TRUE)) {
- X case NGS_ERROR:
- X goto reask_newsgroup;
- X case NGS_ABORT:
- X goto reinp_newsgroup;
- X case NGS_INTR:
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n(Interrupted)\n",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n(Intr)\n",stdout) FLUSH;
- X#endif
- X ng = current_ng;
- X goto reask_newsgroup;
- X case NGS_FOUND:
- X special = TRUE; /* don't skip it if toread==0 */
- X break;
- X case NGS_NOTFOUND:
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n\nNot found--use a or g to add newsgroups\n",
- X stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n\nNot found\n",stdout) FLUSH;
- X#endif
- X goto reask_newsgroup;
- X }
- X#else
- X notincl("/");
- X#endif
- X break;
- X case 'm':
- X#ifndef RELOCATE
- X notincl("m");
- X break;
- X#endif
- X case 'g': /* goto named newsgroup */
- X if (!finish_command(FALSE))
- X /* if they didn't finish command */
- X goto reinp_newsgroup; /* go try something else */
- X for (s = buf+1; *s == ' '; s++);
- X /* skip leading spaces */
- X#ifdef RELOCATE
- X if (!*s && *buf == 'm' && ngname && ng < nextrcline)
- X strcpy(s,ngname);
- X#endif
- X if (isalpha(*s))
- X set_ngname(s);
- X else {
- X if (isdigit(*s)) {
- X int rcnum;
- X rcnum = atoi(s);
- X if (rcnum < nextrcline)
- X set_ngname(rcline[rcnum]);
- X else {
- X printf("\nOnly %d groups. Try again.\n",
- X nextrcline) FLUSH;
- X goto reask_newsgroup;
- X }
- X }
- X else {
- X printf("\nPlease specify a newsgroup.\n") FLUSH;
- X goto reask_newsgroup;
- X }
- X }
- X#ifdef RELOCATE
- X if (!get_ng(ngname,*buf=='m'))
- X /* try to find newsgroup */
- X#else
- X if (!get_ng(ngname,FALSE)) /* try to find newsgroup */
- X#endif
- X ng = current_ng;/* if not found, go nowhere */
- X special = TRUE; /* don't skip it if toread==0 */
- X break;
- X#ifdef DEBUGGING
- X case 'D':
- X printf("\nTries: %d Hits: %d\n",
- X softtries,softtries-softmisses) FLUSH;
- X goto reask_newsgroup;
- X#endif
- X case '!': /* shell escape */
- X if (escapade()) /* do command */
- X goto reinp_newsgroup;
- X /* if rubbed out, re input */
- X goto reask_newsgroup;
- X case Ctl('k'): /* edit global KILL file */
- X edit_kfile();
- X goto reask_newsgroup;
- X case 'c': /* catch up */
- X#ifdef CATCHUP
- reask_catchup:
- X#ifdef VERBOSE
- X IF(verbose)
- X in_char("\nDo you really want to mark everything as read? [yn] ", 'C');
- X ELSE
- X#endif
- X#ifdef TERSE
- X in_char("\nReally? [ynh] ", 'C');
- X#endif
- X setdef(buf,"y");
- X#ifdef VERIFY
- X printcmd();
- X#endif
- X putchar('\n') FLUSH;
- X if (*buf == 'h') {
- X#ifdef VERBOSE
- X printf("Type y or SP to mark all articles as read.\n");
- X printf("Type n to leave articles marked as they are.\n");
- X#else
- X printf("y or SP to mark all read.\n");
- X printf("n to forget it.\n");
- X#endif
- X goto reask_catchup;
- X }
- X else if (*buf != 'y' && *buf != 'n' && *buf != 'q') {
- X printf(hforhelp);
- X settle_down();
- X goto reask_catchup;
- X } else if (*buf == 'y' && ng<nextrcline)
- X catch_up(ng);
- X else
- X retry = TRUE;
- X ng++;
- X#else
- X notincl("c");
- X#endif
- X break;
- X#ifdef USETHREADS
- X case 't':
- X if (!use_threads)
- X printf("\n\nNot running in thread mode.\n");
- X else if (ng < nextrcline && toread[ng] >= TR_NONE) {
- X bool force_threaded = (rcchar[ng] == ':');
- X rcchar[ng] = (force_threaded ? '0' : ':');
- X printf("\n\n%s will %s.\n", rcline[ng],
- X force_threaded ? "always be read threaded"
- X : "be read unthreaded if no thread file exists"
- X ) FLUSH;
- X set_toread(ng);
- X }
- X special = TRUE; /* don't skip it if toread==0 */
- X break;
- X#endif
- X case 'u': /* unsubscribe */
- X if (ng < nextrcline && toread[ng] >= TR_NONE) {
- X /* unsubscribable? */
- X printf(unsubto,rcline[ng]) FLUSH;
- X rcchar[ng] = NEGCHAR;
- X /* unsubscribe to (from?) it */
- X toread[ng] = TR_UNSUB;
- X /* and make line invisible */
- X ng++; /* do an automatic 'n' */
- X }
- X break;
- X case 'h': { /* help */
- X int cmd;
- X
- X if ((cmd = help_ng()) > 0)
- X pushchar(cmd);
- X goto reask_newsgroup;
- X }
- X case 'A':
- X if (ng >= nextrcline)
- X break;
- reask_abandon:
- X#ifdef VERBOSE
- X IF(verbose)
- X in_char("\nAbandon changes to current newsgroup? [yn] ", 'B');
- X ELSE
- X#endif
- X#ifdef TERSE
- X in_char("\nAbandon? [ynh] ", 'B');
- X#endif
- X setdef(buf,"y");
- X#ifdef VERIFY
- X printcmd();
- X#endif
- X putchar('\n') FLUSH;
- X if (*buf == 'h') {
- X#ifdef VERBOSE
- X printf("Type y or SP to abandon the changes to this group since you started trn.\n");
- X printf("Type n to leave the group as it is.\n");
- X#else
- X printf("y or SP to abandon changes to this group.\n");
- X printf("n to forget it.\n");
- X#endif
- X goto reask_abandon;
- X }
- X else if (*buf != 'y' && *buf != 'n' && *buf != 'q') {
- X printf(hforhelp);
- X settle_down();
- X goto reask_abandon;
- X } else if (*buf == 'y')
- X abandon_ng(ng);
- X special = TRUE; /* don't skip it if toread==0 */
- X break;
- X case 'a':
- X#ifndef FINDNEWNG
- X notincl("a");
- X goto reask_newsgroup;
- X#else
- X /* FALL THROUGH */
- X#endif
- X case 'o':
- X#ifdef ONLY
- X {
- X#ifdef FINDNEWNG
- X bool doscan = (*buf == 'a');
- X#endif
- X
- X if (!finish_command(TRUE)) /* get rest of command */
- X goto reinp_newsgroup; /* if rubbed out, try something else */
- X end_only();
- X if (buf[1]) {
- X bool minusd = instr(buf+1,"-d", TRUE) != Nullch;
- X
- X sw_list(buf+1);
- X if (minusd)
- X cwd_check();
- X putchar('\n') FLUSH;
- X#ifdef FINDNEWNG
- X if (doscan && maxngtodo)
- X scanactive();
- X#endif
- X }
- X ng = 0; /* simulate ^ */
- X retry = FALSE;
- X break;
- X }
- X#else
- X notincl("o");
- X goto reask_newsgroup;
- X#endif
- X case '&':
- X if (switcheroo()) /* get rest of command */
- X goto reinp_newsgroup; /* if rubbed out, try something else */
- X goto reask_newsgroup;
- X case 'l': { /* list other newsgroups */
- X if (!finish_command(TRUE)) /* get rest of command */
- X goto reinp_newsgroup; /* if rubbed out, try something else */
- X for (s = buf+1; *s == ' '; s++);
- X /* skip leading spaces */
- X sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
- X resetty();
- X if (doshell(sh,cmd_buf))
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs(" (Error from newsgroups program)\n",
- X stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("(Error)\n",stdout) FLUSH;
- X#endif
- X noecho();
- X crmode();
- X goto reask_newsgroup;
- X }
- X#ifdef USETHREADS
- X case 'U': case '+':
- X#endif
- X case '.': case '=':
- X case 'y': case 'Y': case '\t': /* do normal thing */
- X if (ng >= nextrcline) {
- X fputs("\nNot on a newsgroup.",stdout) FLUSH;
- X goto reask_newsgroup;
- X }
- X#ifdef USETHREADS
- X else if (*buf == '+' || *buf == 'U' || *buf == '=') {
- X buf[1] = '\0';
- X s = savestr(buf);
- X }
- X#else
- X if (*buf == '=')
- X s = savestr("=");
- X#endif
- X else if (*buf == '.') { /* start command? */
- X if (!finish_command(FALSE)) /* get rest of command */
- X goto reinp_newsgroup;
- X s = savestr(buf+1);
- X /* do_newsgroup will free it */
- X }
- X else
- X s = Nullch;
- X if (toread[ng])
- X retry = TRUE;
- X switch (do_newsgroup(s)) {
- X case NG_ERROR:
- X case NG_NORM:
- X ng++;
- X break;
- X case NG_ASK:
- X goto reask_newsgroup;
- X case NG_SELPRIOR:
- X *buf = 'p';
- X goto do_command;
- X case NG_SELNEXT:
- X *buf = 'n';
- X goto do_command;
- X case NG_MINUS:
- X ng = recent_ng; /* recall previous newsgroup */
- X special = TRUE; /* don't skip it if toread==0 */
- X break;
- X }
- X break;
- X#ifdef STRICTCR
- X case '\n':
- X fputs(badcr,stdout) FLUSH;
- X goto reask_newsgroup;
- X#endif
- X case 'v':
- X printf("\n%s",rnid);
- X printf("\n%s",patchlevel);
- X printf("\nSend bugs to davison@borland.com\n") FLUSH;
- X goto reask_newsgroup;
- X default:
- X printf("\n%s",hforhelp) FLUSH;
- X settle_down();
- X goto reask_newsgroup;
- X }
- X }
- X } while (retry);
- X }
- X
- X /* now write .newsrc back out */
- X
- X write_rc();
- X
- X if (oh_for_the_good_old_days)
- X get_old_rc();
- X
- X finalize(0); /* and exit */
- X}
- X
- X/* set current newsgroup */
- X
- void
- set_ngname(what)
- char *what;
- X{
- X int len = strlen(what)+1;
- X
- X growstr(&ngname,&ngnlen,len);
- X strcpy(ngname,what);
- X growstr(&ngdir,&ngdlen,len);
- X strcpy(ngdir,getngdir(ngname));
- X}
- X
- static char *myngdir;
- static int ngdirlen = 0;
- X
- char *
- getngdir(ngnam)
- char *ngnam;
- X{
- X register char *s;
- X
- X growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
- X strcpy(myngdir,ngnam);
- X for (s = myngdir; *s; s++)
- X if (*s == '.')
- X *s = '/';
- X return myngdir;
- X}
- END_OF_FILE
- if test 15991 -ne `wc -c <'rn.c'`; then
- echo shar: \"'rn.c'\" unpacked with wrong size!
- fi
- # end of 'rn.c'
- fi
- if test -f 'util.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'util.c'\"
- else
- echo shar: Extracting \"'util.c'\" \(14626 characters\)
- sed "s/^X//" >'util.c' <<'END_OF_FILE'
- X/* $Id: util.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
- X *
- X * $Log: util.c,v $
- X * Revision 4.4 1991/09/09 20:27:37 sob
- X * release 4.4
- X *
- X *
- X *
- X */
- X/* This software is Copyright 1991 by Stan Barber.
- X *
- X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
- X * use this software as long as: there is no monetary profit gained
- X * specifically from the use or reproduction of this software, it is not
- X * sold, rented, traded or otherwise marketed, and this copyright notice is
- X * included prominently in any copy made.
- X *
- X * The author make no claims as to the fitness or correctness of this software
- X * for any use whatsoever, and it is provided as is. Any use of this software
- X * is at the user's own risk.
- X */
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "final.h"
- X#include "INTERN.h"
- X#include "util.h"
- X
- X#ifdef TZSET
- X#include <time.h>
- X#else
- X#include <sys/time.h>
- X#include <sys/timeb.h>
- X#endif
- X
- void
- util_init()
- X{
- X ;
- X}
- X
- X/* fork and exec a shell command */
- X
- int
- doshell(shl,s)
- char *s, *shl;
- X{
- X int status, pid, w;
- X char *shell;
- X
- X#ifdef SIGTSTP
- X sigset(SIGTSTP,SIG_DFL);
- X sigset(SIGTTOU,SIG_DFL);
- X sigset(SIGTTIN,SIG_DFL);
- X#endif
- X if (shl != Nullch)
- X shell = shl;
- X else if ((shell = getenv("SHELL")) == Nullch || !*shell)
- X shell = PREFSHELL;
- X if ((pid = vfork()) == 0) {
- X#ifdef SERVER
- X int i;
- X
- X /* This is necessary to keep bourne shell from puking */
- X
- X for (i = 3; i < 10; ++i)
- X close(i);
- X#endif /* SERVER */
- X
- X if (*s)
- X execl(shell, shell, "-c", s, Nullch);
- X else
- X execl(shell, shell, Nullch, Nullch, Nullch);
- X _exit(127);
- X }
- X signal(SIGINT, SIG_IGN);
- X#ifdef SIGQUIT
- X signal(SIGQUIT, SIG_IGN);
- X#endif
- X waiting = TRUE;
- X while ((w = wait(&status)) != pid)
- X if (w == -1 && errno != EINTR)
- X break;
- X if (w == -1)
- X status = -1;
- X waiting = FALSE;
- X sigset(SIGINT, int_catcher); /* always catch interrupts */
- X#ifdef SIGQUIT
- X signal(SIGQUIT, SIG_DFL);
- X#endif
- X#ifdef SIGTSTP
- X sigset(SIGTSTP,stop_catcher);
- X sigset(SIGTTOU,stop_catcher);
- X sigset(SIGTTIN,stop_catcher);
- X#endif
- X return status;
- X}
- X
- static char nomem[] = "rn: out of memory!\n";
- X
- X/* paranoid version of malloc */
- X
- char *
- safemalloc(size)
- MEM_SIZE size;
- X{
- X char *ptr;
- X char *malloc();
- X
- X ptr = malloc(size ? size : (MEM_SIZE)1);
- X if (ptr == Nullch) {
- X fputs(nomem,stdout) FLUSH;
- X sig_catcher(0);
- X }
- X return ptr;
- X}
- X
- X/* paranoid version of realloc */
- X
- char *
- saferealloc(where,size)
- char *where;
- MEM_SIZE size;
- X{
- X char *ptr;
- X char *realloc();
- X
- X ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */
- X if (ptr == Nullch) {
- X fputs(nomem,stdout) FLUSH;
- X sig_catcher(0);
- X }
- X return ptr;
- X}
- X
- X/* safe version of string copy */
- X
- char *
- safecpy(to,from,len)
- char *to;
- register char *from;
- register int len;
- X{
- X register char *dest = to;
- X
- X if (from != Nullch)
- X for (len--; len && (*dest++ = *from++); len--) ;
- X *dest = '\0';
- X return to;
- X}
- X
- X/* safe version of string concatenate, with \n deletion and space padding */
- X
- char *
- safecat(to,from,len)
- char *to;
- register char *from;
- register int len;
- X{
- X register char *dest = to;
- X
- X len--; /* leave room for null */
- X if (*dest) {
- X while (len && *dest++) len--;
- X if (len) {
- X len--;
- X *(dest-1) = ' ';
- X }
- X }
- X if (from != Nullch)
- X while (len && (*dest++ = *from++)) len--;
- X if (len)
- X dest--;
- X if (*(dest-1) == '\n')
- X dest--;
- X *dest = '\0';
- X return to;
- X}
- X
- X/* copy a string up to some (non-backslashed) delimiter, if any */
- X
- char *
- cpytill(to,from,delim)
- register char *to, *from;
- register int delim;
- X{
- X for (; *from; from++,to++) {
- X if (*from == '\\' && from[1] == delim)
- X from++;
- X else if (*from == delim)
- X break;
- X *to = *from;
- X }
- X *to = '\0';
- X return from;
- X}
- X
- X/* return ptr to little string in big string, NULL if not found */
- X
- char *
- instr(big, little, case_matters)
- char *big, *little;
- int case_matters;
- X{
- X register char *t, *s, *x;
- X
- X for (t = big; *t; t++) {
- X for (x=t,s=little; *s; x++,s++) {
- X if (!*x)
- X return Nullch;
- X if (case_matters == TRUE) {
- X if(*s != *x)
- X break;
- X } else {
- X register char c,d;
- X if (isupper(*s))
- X c = tolower(*s);
- X else
- X c = *s;
- X if (isupper(*x))
- X d = tolower(*x);
- X else
- X d = *x;
- X if ( c != d )
- X break;
- X }
- X }
- X if (!*s)
- X return t;
- X }
- X return Nullch;
- X}
- X
- X/* effective access */
- X
- X#ifdef SETUIDGID
- int
- eaccess(filename, mod)
- char *filename;
- int mod;
- X{
- X int protection, euid;
- X
- X mod &= 7; /* remove extraneous garbage */
- X if (stat(filename, &filestat) < 0)
- X return -1;
- X euid = geteuid();
- X if (euid == ROOTID)
- X return 0;
- X protection = 7 & (filestat.st_mode >>
- X (filestat.st_uid == euid ? 6 :
- X (filestat.st_gid == getegid() ? 3 : 0)
- X ));
- X if ((mod & protection) == mod)
- X return 0;
- X errno = EACCES;
- X return -1;
- X}
- X#endif
- X
- X/*
- X * Get working directory
- X */
- X#ifndef GETWD
- X#ifdef GETCWD
- char *
- getwd(np)
- char *np;
- X{
- X char * name;
- X extern char * getcwd();
- X name = getcwd(np,512);
- X return(name);
- X}
- X#else
- char *
- getwd(np) /* shorter but slower */
- char *np;
- X{
- X FILE *popen();
- X FILE *pipefp = popen("/bin/pwd","r");
- X
- X if (pipefp == Nullfp) {
- X printf("Can't run /bin/pwd\n") FLUSH;
- X finalize(1);
- X }
- X fgets(np,512,pipefp);
- X np[strlen(np)-1] = '\0'; /* wipe out newline */
- X pclose(pipefp);
- X return np;
- X}
- X#endif
- X#endif
- X/* just like fgets but will make bigger buffer as necessary */
- X
- char *
- get_a_line(original_buffer,buffer_length,fp)
- char *original_buffer;
- register int buffer_length;
- XFILE *fp;
- X{
- X register int bufix = 0;
- X register int nextch;
- X register char *some_buffer_or_other = original_buffer;
- X
- X do {
- X if (bufix >= buffer_length) {
- X buffer_length *= 2;
- X if (some_buffer_or_other == original_buffer) {
- X /* currently static? */
- X some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
- X strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
- X /* so we must copy it */
- X }
- X else { /* just grow in place, if possible */
- X some_buffer_or_other = saferealloc(some_buffer_or_other,
- X (MEM_SIZE)buffer_length+1);
- X }
- X }
- X if ((nextch = getc(fp)) == EOF)
- X return Nullch;
- X some_buffer_or_other[bufix++] = (char) nextch;
- X } while (nextch && nextch != '\n');
- X some_buffer_or_other[bufix] = '\0';
- X len_last_line_got = bufix;
- X return some_buffer_or_other;
- X}
- X
- X/* copy a string to a safe spot */
- X
- char *
- savestr(str)
- char *str;
- X{
- X register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
- X
- X strcpy(newaddr,str);
- X return newaddr;
- X}
- X
- int
- makedir(dirname,nametype)
- register char *dirname;
- int nametype;
- X{
- X#ifdef MAKEDIR
- X register char *end;
- X register char *s;
- X char tmpbuf[1024];
- X register char *tbptr = tmpbuf+5;
- X
- X for (end = dirname; *end; end++) ; /* find the end */
- X if (nametype == MD_FILE) { /* not to create last component? */
- X for (--end; end != dirname && *end != '/'; --end) ;
- X if (*end != '/')
- X return 0; /* nothing to make */
- X *end = '\0'; /* isolate file name */
- X }
- X strcpy(tmpbuf,"mkdir");
- X
- X s = end;
- X for (;;) {
- X if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) {
- X /* does this much exist as a dir? */
- X *s = '/'; /* mark this as existing */
- X break;
- X }
- X s = rindex(dirname,'/'); /* shorten name */
- X if (!s) /* relative path! */
- X break; /* hope they know what they are doing */
- X *s = '\0'; /* mark as not existing */
- X }
- X
- X for (s=dirname; s <= end; s++) { /* this is grody but efficient */
- X if (!*s) { /* something to make? */
- X sprintf(tbptr," %s",dirname);
- X tbptr += strlen(tbptr); /* make it, sort of */
- X *s = '/'; /* mark it made */
- X }
- X }
- X if (nametype == MD_DIR) /* don't need final slash unless */
- X *end = '\0'; /* a filename follows the dir name */
- X
- X return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));
- X /* exercise our faith */
- X#else
- X sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
- X return doshell(sh,cmd_buf);
- X#endif
- X}
- X
- X#ifdef SETENV
- static bool firstsetenv = TRUE;
- extern char **environ;
- X
- void
- setenv(nam,val)
- char *nam, *val;
- X{
- X register int i=envix(nam); /* where does it go? */
- X
- X if (!environ[i]) { /* does not exist yet */
- X if (firstsetenv) { /* need we copy environment? */
- X int j;
- X#ifndef lint
- X char **tmpenv = (char**) /* point our wand at memory */
- X safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
- X#else
- X char **tmpenv = Null(char **);
- X#endif /* lint */
- X
- X firstsetenv = FALSE;
- X for (j=0; j<i; j++) /* copy environment */
- X tmpenv[j] = environ[j];
- X environ = tmpenv; /* tell exec where it is now */
- X }
- X#ifndef lint
- X else
- X environ = (char**) saferealloc((char*) environ,
- X (MEM_SIZE) (i+2) * sizeof(char*));
- X /* just expand it a bit */
- X#endif /* lint */
- X environ[i+1] = Nullch; /* make sure it's null terminated */
- X }
- X environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
- X /* this may or may not be in */
- X /* the old environ structure */
- X sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
- X}
- X
- int
- envix(nam)
- char *nam;
- X{
- X register int i, len = strlen(nam);
- X
- X for (i = 0; environ[i]; i++) {
- X if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
- X break; /* strnEQ must come first to avoid */
- X } /* potential SEGV's */
- X return i;
- X}
- X#endif
- X
- void
- notincl(feature)
- char *feature;
- X{
- X printf("\nNo room for feature \"%s\" on this machine.\n",feature) FLUSH;
- X}
- X
- char *
- getval(nam,def)
- char *nam,*def;
- X{
- X char *val;
- X
- X if ((val = getenv(nam)) == Nullch || !*val)
- X val = def;
- X return val;
- X}
- X
- X/* grow a static string to at least a certain length */
- X
- void
- growstr(strptr,curlen,newlen)
- char **strptr;
- int *curlen;
- int newlen;
- X{
- X if (newlen > *curlen) { /* need more room? */
- X if (*curlen)
- X *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
- X else
- X *strptr = safemalloc((MEM_SIZE)newlen);
- X *curlen = newlen;
- X }
- X}
- X
- void
- setdef(buffer,dflt)
- char *buffer,*dflt;
- X{
- X#ifdef STRICTCR
- X if (*buffer == ' ')
- X#else
- X if (*buffer == ' ' || *buffer == '\n')
- X#endif
- X {
- X if (*dflt == '^' && isupper(dflt[1]))
- X *buffer = Ctl(dflt[1]);
- X else
- X *buffer = *dflt;
- X }
- X}
- X
- X#ifdef SERVER
- int nntp_get(buf, len)
- char *buf;
- int len;
- X{
- X int n;
- X#ifdef HAVESIGHOLD
- X sighold(SIGINT);
- X#endif
- X n = get_server(buf, len);
- X#ifdef HAVESIGHOLD
- X sigrelse(SIGINT);
- X#endif
- X return n;
- X}
- X#endif
- X
- X#ifndef STRFTIME
- X/*
- X * strftime: print formatted information about a given time.
- X * Adapted from the routine by Eric R. Smith, Michal Jaegermann,
- X * Arnold Robins, and Paul Close.
- X */
- X
- X/* Configuration choices for %x and %X */
- X
- X#undef LOCAL_DDMMYY /* choose DD/MM/YY instead of MM/DD/YY */
- X#undef LOCAL_DOTTIME /* choose HH.MM.SS instead of HH:MM:SS */
- X
- static char *mth_name[] = {
- X "January", "February", "March", "April", "May", "June",
- X "July", "August", "September", "October", "November", "December"
- X};
- X
- static char *day_name[] = {
- X "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
- X "Saturday"
- X};
- X
- X#ifdef TZSET
- extern char *tzname[];
- X#endif
- X
- int
- strftime(str, maxsize, fmt, ts)
- char *str;
- int maxsize;
- char *fmt;
- struct tm *ts;
- X{
- X int num = 0, len;
- X char ch;
- X char *putstr, *s;
- X char tmpbuf[80];
- X
- X if (maxsize-- <= 0)
- X return 0;
- X
- X for (;;) {
- X if (!(ch = *fmt++))
- X break;
- X if (num == maxsize) {
- X num = 0;
- X break;
- X }
- X if (ch != '%') {
- X *str++ = ch;
- X num++;
- X continue;
- X }
- X /* assume the finished product will be sprintf'ed into tmpbuf */
- X putstr = tmpbuf;
- X
- X switch (ch = *fmt++) {
- X case 'A':
- X case 'a':
- X if (ts->tm_wday < 0 || ts->tm_wday > 6)
- X putstr = "?";
- X else
- X if (ch == 'A')
- X putstr = day_name[ts->tm_wday];
- X else
- X sprintf(tmpbuf, "%-.3s", day_name[ts->tm_wday]);
- X break;
- X case 'B':
- X case 'b':
- X case 'h':
- X if (ts->tm_mon < 0 || ts->tm_mon > 11)
- X putstr = "?";
- X else if (ch == 'B')
- X putstr = mth_name[ts->tm_mon];
- X else
- X sprintf(tmpbuf, "%-.3s", mth_name[ts->tm_mon]);
- X break;
- X case 'C':
- X strftime(tmpbuf, sizeof tmpbuf, "%A, %B %e, %Y", ts);
- X break;
- X case 'c':
- X strftime(tmpbuf, sizeof tmpbuf, "%x %X", ts);
- X break;
- X case 'D':
- X#ifndef LOCAL_DDMMYY
- X case 'x':
- X#endif
- X strftime(tmpbuf, sizeof tmpbuf, "%m/%d/%y", ts);
- X break;
- X case 'd':
- X sprintf(tmpbuf, "%02d", ts->tm_mday);
- X break;
- X case 'e': /* day of month, blank padded */
- X sprintf(tmpbuf, "%2d", ts->tm_mday);
- X break;
- X case 'H':
- X sprintf(tmpbuf, "%02d", ts->tm_hour);
- X break;
- X case 'I':
- X {
- X int n;
- X
- X n = ts->tm_hour;
- X if (n == 0)
- X n = 12;
- X else if (n > 12)
- X n -= 12;
- X sprintf(tmpbuf, "%02d", n);
- X break;
- X }
- X case 'j':
- X sprintf(tmpbuf, "%03d", ts->tm_yday + 1);
- X break;
- X case 'm':
- X sprintf(tmpbuf, "%02d", ts->tm_mon + 1);
- X break;
- X case 'M':
- X sprintf(tmpbuf, "%02d", ts->tm_min);
- X break;
- X case 'p':
- X putstr = (ts->tm_hour < 12) ? "AM" : "PM";
- X break;
- X case 'r':
- X strftime(tmpbuf, sizeof tmpbuf, "%I:%M:%S %p", ts);
- X break;
- X case 'R':
- X strftime(tmpbuf, sizeof tmpbuf, "%H:%M", ts);
- X break;
- X case 'S':
- X sprintf(tmpbuf, "%02d", ts->tm_sec);
- X break;
- X case 'T':
- X#ifndef LOCAL_DOTTIME
- X case 'X':
- X#endif
- X strftime(tmpbuf, sizeof tmpbuf, "%H:%M:%S", ts);
- X break;
- X case 'U': /* week of year - starting Sunday */
- X sprintf(tmpbuf, "%02d", (ts->tm_yday - ts->tm_wday + 10) / 7);
- X break;
- X case 'W': /* week of year - starting Monday */
- X sprintf(tmpbuf, "%02d", (ts->tm_yday - ((ts->tm_wday + 6) % 7)
- X + 10) / 7);
- X break;
- X case 'w':
- X sprintf(tmpbuf, "%d", ts->tm_wday);
- X break;
- X case 'y':
- X sprintf(tmpbuf, "%02d", ts->tm_year % 100);
- X break;
- X#ifdef LOCAL_DOTTIME
- X case 'X':
- X strftime(tmpbuf, sizeof tmpbuf, "%H.%M.%S", ts);
- X break;
- X#endif
- X#ifdef LOCAL_DDMMYY
- X case 'x':
- X strftime(tmpbuf, sizeof tmpbuf, "%d/%m/%y", ts);
- X break;
- X#endif
- X case 'Y':
- X sprintf(tmpbuf, "%d", ts->tm_year + 1900);
- X break;
- X case 'Z':
- X#ifdef TZSET
- X sprintf(tmpbuf, "%s", tzname[ts->tm_isdst]);
- X#else
- X sprintf(tmpbuf, "%s", ts->tm_zone);
- X#endif
- X break;
- X case '%':
- X case '\0':
- X putstr = "%";
- X break;
- X case 'n': /* same as \n */
- X putstr = "\n";
- X break;
- X case 't': /* same as \t */
- X putstr = "\n";
- X break;
- X default:
- X sprintf(tmpbuf, "%%%c", ch);
- X break;
- X }
- X len = strlen(putstr);
- X num += len;
- X if (num > maxsize) {
- X len -= num - maxsize;
- X num = 0;
- X ch = '\0';
- X }
- X strncpy(str, putstr, len);
- X str += len;
- X if (!ch)
- X break;
- X }
- X *str = '\0';
- X return num;
- X}
- X#endif /* no STRFTIME */
- END_OF_FILE
- if test 14626 -ne `wc -c <'util.c'`; then
- echo shar: \"'util.c'\" unpacked with wrong size!
- fi
- # end of 'util.c'
- fi
- echo shar: End of archive 6 \(of 13\).
- cp /dev/null ark6isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 13 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-